package com.gzx.bi.xxljob;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.gzx.bi.modular.current.entity.GzxCurrentId;
import com.gzx.bi.modular.current.service.GzxCurrentIdService;
import com.gzx.bi.modular.goals.advance.entity.AdvancePayments;
import com.gzx.bi.modular.goals.advance.service.AdvancePaymentsService;
import com.gzx.bi.modular.plan.bo.GzxProjectPlanXxlEditBo;
import com.gzx.bi.modular.plan.service.GzxProjectPlanXxlJobService;
import com.gzx.bi.modular.repayment.client.entity.GzxRepaymentClient;
import com.gzx.bi.modular.repayment.client.service.GzxRepaymentClientService;
import com.gzx.bi.modular.repayment.subsidiary.entity.GzxRepaymentSubsidiary;
import com.gzx.bi.modular.repayment.subsidiary.service.GzxRepaymentSubsidiaryService;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import vip.xiaonuo.common.tenant.TenantContext;
import vip.xiaonuo.common.util.CommonDateUtil;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;

/**
 * @author zjt
 * @description
 * @date 2025/4/27 17:17
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class SyncProjectPlanDataXxlJob {

    private final GzxProjectPlanXxlJobService projectPlanXxlJobService;

    private final GzxCurrentIdService currentIdService;

    private final GzxRepaymentClientService repaymentClientService;

    private final GzxRepaymentSubsidiaryService repaymentSubsidiaryService;

    private final AdvancePaymentsService advancePaymentsService;

    /**
     * 委案金额，上月人力
     * 每月1号执行一次
     */
    @XxlJob("syncLastMonthAmountXxlJobHandler")
    public void syncLastMonthAmountXxlJobHandler() {
        log.info("Xxl-Job：保存上月数据到本月");
        try {
            TenantContext.disableTenantFilter();
            projectPlanXxlJobService.saveLastMonthData();
        } catch (Exception e) {
            log.error("Xxl-Job：保存上月数据到本月，出现异常", e);
        } finally {
            TenantContext.enableTenantFilter();
            TenantContext.clear();
        }
    }

    /**
     * 同步当月分公司上报还款数据
     */
    @XxlJob("syncCurMthBranchRepXxlJobHandler")
    public void syncCurMthBranchRep() {
        XxlJobHelper.log("Bi模块--XxlJob定时任务启动---------同步分公司上报还款数据------>" + CommonDateUtil.getCurrentTimeStr());
        List<GzxRepaymentSubsidiary> repaymentSubsidiaryList = repaymentSubsidiaryService.selectList(Wrappers.<GzxRepaymentSubsidiary>lambdaQuery()
                .ge(GzxRepaymentSubsidiary::getRepaymentDate, CommonDateUtil.getCurrentMonthFirstDay()));
        //根据项目和批次进行分组
        Map<String, List<GzxRepaymentSubsidiary>> repaymentSubsidiaryMap = repaymentSubsidiaryList.stream()
                .collect(Collectors.groupingBy(subsidiary -> subsidiary.getProjectCode() + "@" + subsidiary.getBatch() + "@" + subsidiary.getDeptId()));
        for (Map.Entry<String, List<GzxRepaymentSubsidiary>> repaymentClient : repaymentSubsidiaryMap.entrySet()) {
            //累计金额
            BigDecimal monthlySubsidiaryAmount = repaymentClient.getValue().stream().map(GzxRepaymentSubsidiary::getRepaymentAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            GzxProjectPlanXxlEditBo projectPlanXxlEditBo = new GzxProjectPlanXxlEditBo();
            projectPlanXxlEditBo.setBranchRepay(monthlySubsidiaryAmount);
            projectPlanXxlEditBo.setProjectCode(repaymentClient.getKey().split("@")[0]);
            projectPlanXxlEditBo.setBatch(repaymentClient.getKey().split("@")[1]);
            projectPlanXxlEditBo.setDeptId(Long.valueOf(repaymentClient.getKey().split("@")[2]));
            projectPlanXxlJobService.modifyRepaymentAmount(projectPlanXxlEditBo);
        }
    }

    /**
     * 同步当月甲方还款数据
     */
    @XxlJob("syncCurMthPartyARepXxlJobHandler")
    public void syncCurMthPartyARep() {
        XxlJobHelper.log("Bi模块--开始同步甲方还款数据--->" + CommonDateUtil.getCurrentTimeStr());
        try {
            TenantContext.disableTenantFilter();
            GzxCurrentId currentIdObj = currentIdService.getCurrentIdByType("ClientRepaymentMaxSyncId");
            if (currentIdObj == null) {
                log.warn("未找到ClientRepaymentMaxSyncId配置，跳过同步");
                return;
            }
            List<GzxRepaymentClient> repaymentClientList = repaymentClientService.selectList(
                    Wrappers.<GzxRepaymentClient>lambdaQuery()
                            .gt(GzxRepaymentClient::getId, currentIdObj.getCurrentId())
                            .ge(GzxRepaymentClient::getRepaymentDate, CommonDateUtil.getCurrentMonthFirstDay())
                            .isNotNull(GzxRepaymentClient::getBatch)
            );
            if (repaymentClientList.isEmpty()) {
                log.info("没有新的还款数据需要同步");
                return;
            }
            processRepaymentData(repaymentClientList, GzxProjectPlanXxlEditBo::setTotalRepay);
            // 更新最大ID
            long maxId = repaymentClientList.stream()
                    .mapToLong(GzxRepaymentClient::getId)
                    .max()
                    .orElse(0L);
            currentIdObj.setCurrentId(maxId);
            currentIdService.updateCurrentId(currentIdObj);
            XxlJobHelper.log("成功同步甲方还款数据，共处理{}条记录", repaymentClientList.size());
        } catch (Exception e) {
            log.error("同步甲方还款数据出现异常：", e);
            XxlJobHelper.log("同步甲方还款数据失败：" + e.getMessage());
        } finally {
            TenantContext.enableTenantFilter();
            TenantContext.clear();
        }
    }

    /**
     * 同步上月1号至上月今日甲方还款金额
     * 每天执行一次
     */
    @XxlJob("syncLastMthPeriodRepXxlJobHandler")
    public void syncLastMthPeriodRep() {
        XxlJobHelper.log("Bi模块--开始同步上月1号至上月今日甲方还款金额--->" + CommonDateUtil.getCurrentTimeStr());
        try {
            TenantContext.disableTenantFilter();
            String startDate = CommonDateUtil.getLastMonthFirstDay() + " 00:00:00";
            String endDate = CommonDateUtil.getLastMonthToday() + " 23:59:59";
            List<GzxRepaymentClient> repaymentClientList = repaymentClientService.selectList(
                    Wrappers.<GzxRepaymentClient>lambdaQuery()
                            .between(GzxRepaymentClient::getRepaymentDate, startDate, endDate)
            );
            if (repaymentClientList.isEmpty()) {
                log.info("上月同期没有还款数据");
                return;
            }
            processRepaymentData(repaymentClientList, GzxProjectPlanXxlEditBo::setLastTotalRepay);
            XxlJobHelper.log("成功同步月度环比甲方还款数据，共处理{}条记录", repaymentClientList.size());
        } catch (Exception e) {
            log.error("同步月度环比甲方还款数据出现异常：", e);
            XxlJobHelper.log("同步月度环比甲方还款数据失败：" + e.getMessage());
        } finally {
            TenantContext.enableTenantFilter();
            TenantContext.clear();
        }
    }

    /**
     * 同步昨日环比甲方还款数据
     */
    @XxlJob("syncYesterdayRepXxlJobHandler")
    public void syncYesterdayRep() {
        XxlJobHelper.log("Bi模块--开始同步昨日环比甲方还款数据--->" + CommonDateUtil.getCurrentTimeStr());
        try {
            TenantContext.disableTenantFilter();
            String yesterday = CommonDateUtil.getOffsetDateStr(-1);
            String startDate = CommonDateUtil.getCurrentMonthFirstDay() + " 00:00:00";
            String endDate = yesterday + " 23:59:59";
            List<GzxRepaymentClient> repaymentClientList = repaymentClientService.selectList(
                    Wrappers.<GzxRepaymentClient>lambdaQuery()
                            .between(GzxRepaymentClient::getRepaymentDate, startDate, endDate)
            );
            if (repaymentClientList.isEmpty()) {
                log.info("昨日没有还款数据");
                return;
            }
            processRepaymentData(repaymentClientList, GzxProjectPlanXxlEditBo::setYesterdayRepay);
            XxlJobHelper.log("成功同步昨日环比甲方还款数据，共处理{}条记录", repaymentClientList.size());
        } catch (Exception e) {
            log.error("同步昨日环比甲方还款数据出现异常：", e);
            XxlJobHelper.log("同步昨日环比甲方还款数据失败：" + e.getMessage());
        } finally {
            TenantContext.enableTenantFilter();
            TenantContext.clear();
        }
    }

    /**
     * 同步上月环比垫付数据
     */
    @XxlJob("syncLastMthPeriodAdvXxlJobHandler")
    public void syncLastMthPeriodAdv() {
        XxlJobHelper.log("Bi模块--开始同步上月环比垫付数据--->" + CommonDateUtil.getCurrentTimeStr());
        try {
            TenantContext.disableTenantFilter();
            List<AdvancePayments> advancePaymentsList = advancePaymentsService.getLastMonthAdvancePayments();
            if (advancePaymentsList.isEmpty()) {
                log.info("上月没有垫付数据");
                XxlJobHelper.log("上月没有垫付数据需要同步");
                return;
            }
            processAdvanceData(advancePaymentsList, GzxProjectPlanXxlEditBo::setLastAdvance);
            XxlJobHelper.log("成功同步上月环比垫付数据，共处理{}条记录", advancePaymentsList.size());
        } catch (Exception e) {
            log.error("同步上月环比垫付数据出现异常：", e);
            XxlJobHelper.log("同步上月环比垫付数据失败：" + e.getMessage());
        } finally {
            TenantContext.enableTenantFilter();
            TenantContext.clear();
        }
    }

    /**
     * 同步昨日垫付数据
     */
    @XxlJob("syncYestAdvXxlJobHandler")
    public void syncYestAdv() {
        XxlJobHelper.log("Bi模块--开始同步昨日垫付数据--->" + CommonDateUtil.getCurrentTimeStr());
        try {
            TenantContext.disableTenantFilter();
            List<AdvancePayments> advancePaymentsList = advancePaymentsService.getYesterdayAdvancePayments();

            if (advancePaymentsList.isEmpty()) {
                log.info("昨日没有垫付数据");
                XxlJobHelper.log("昨日没有垫付数据需要同步");
                return;
            }
            processAdvanceData(advancePaymentsList, GzxProjectPlanXxlEditBo::setYesterdayAdvance);
            XxlJobHelper.log("成功同步昨日垫付数据，共处理{}条记录", advancePaymentsList.size());
        } catch (Exception e) {
            log.error("同步昨日垫付数据出现异常：", e);
            XxlJobHelper.log("同步昨日垫付数据失败：" + e.getMessage());
        } finally {
            TenantContext.enableTenantFilter();
            TenantContext.clear();
        }
    }

    /**
     * 处理垫付数据公共逻辑
     */
    private void processAdvanceData(List<AdvancePayments> advancePaymentsList,
                                    BiConsumer<GzxProjectPlanXxlEditBo, BigDecimal> amountSetter) {
        // 根据项目和批次进行分组
        Map<String, List<AdvancePayments>> advancePaymentsMap = advancePaymentsList.stream()
                .collect(Collectors.groupingBy(payment -> payment.getProject() + "@" + payment.getBatch()));
        for (Map.Entry<String, List<AdvancePayments>> entry : advancePaymentsMap.entrySet()) {
            String[] keyParts = entry.getKey().split("@");
            String projectCode = keyParts[0];
            String batch = keyParts[1];
            // 计算累计金额
            BigDecimal totalAmount = entry.getValue().stream()
                    .map(AdvancePayments::getAdvancedPaymentAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            // 构建编辑对象
            GzxProjectPlanXxlEditBo editBo = new GzxProjectPlanXxlEditBo();
            editBo.setProjectCode(projectCode);
            editBo.setBatch(batch);
            // 设置金额
            amountSetter.accept(editBo, totalAmount);
            // 更新项目计划
            projectPlanXxlJobService.modifyRepaymentAmount(editBo);
        }
    }

    /**
     * 处理还款数据公共逻辑
     */
    private void processRepaymentData(List<GzxRepaymentClient> repaymentClientList, BiConsumer<GzxProjectPlanXxlEditBo, BigDecimal> amountSetter) {
        // 根据项目和批次进行分组
        Map<String, List<GzxRepaymentClient>> repaymentClientMap = repaymentClientList.stream()
                .collect(Collectors.groupingBy(client -> client.getProjectCode() + "@" + client.getBatch() + "@" + client.getDeptId()));
        for (Map.Entry<String, List<GzxRepaymentClient>> entry : repaymentClientMap.entrySet()) {
            String[] keyParts = entry.getKey().split("@");
            String projectCode = keyParts[0];
            String batch = keyParts[1];
            Long deptId = Long.valueOf(keyParts[2]);
            // 计算累计金额
            BigDecimal totalAmount = entry.getValue().stream()
                    .map(GzxRepaymentClient::getRepaymentAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            // 按天分组计算金额
            Map<String, BigDecimal> dayMap = entry.getValue().stream()
                    .collect(Collectors.groupingBy(
                            dto -> CommonDateUtil.convertToDate(dto.getRepaymentDate()),
                            Collectors.reducing(
                                    BigDecimal.ZERO,
                                    GzxRepaymentClient::getRepaymentAmount,
                                    BigDecimal::add)));
            // 构建编辑对象
            GzxProjectPlanXxlEditBo editBo = new GzxProjectPlanXxlEditBo();
            editBo.setProjectCode(projectCode);
            editBo.setBatch(batch);
            editBo.setDeptId(deptId);
            // 设置金额（通过函数式接口实现不同场景的设置）
            amountSetter.accept(editBo, totalAmount);
            if (editBo.getTotalRepay() != null) {
                editBo.setDayRepaymentDetail(new TreeMap<>(dayMap));
            }
            // 更新项目计划
            projectPlanXxlJobService.modifyRepaymentAmount(editBo);
        }
    }
}
